package TreeHole.save;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.exceptions.SaveFileLoadError;
import com.megacrit.cardcrawl.helpers.AsyncSaver;
import com.megacrit.cardcrawl.helpers.SaveHelper;
import com.megacrit.cardcrawl.relics.BottledFlame;
import com.megacrit.cardcrawl.relics.BottledLightning;
import com.megacrit.cardcrawl.relics.BottledTornado;
import com.megacrit.cardcrawl.saveAndContinue.SaveFile;
import com.megacrit.cardcrawl.saveAndContinue.SaveFileObfuscator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;

public class SaveAndContinueFore {
    public static final Logger logger = LogManager.getLogger(SaveAndContinueFore.class.getName());

    public static SaveFile makeCopy(){
        SaveFile foreSave = new SaveFile(SaveFile.SaveType.ENTER_ROOM);
        logger.info("MAKECOPY===当前怪物数量："+foreSave.monster_list.size()+" ，怪物列表："+foreSave.monster_list.toString()+" ===");
        logger.info("MAKECOPY===当前BOSS数量："+foreSave.boss_list.size()+" ，BOSS列表："+foreSave.boss_list.toString()+" ===");
        //deep set copy
        foreSave.event_list = new ArrayList<>(foreSave.event_list);
        foreSave.one_time_event_list = new ArrayList<>(foreSave.one_time_event_list);
        foreSave.event_chances = new ArrayList<>(foreSave.event_chances);
        foreSave.monster_list = new ArrayList<>(foreSave.monster_list);
        foreSave.elite_monster_list = new ArrayList<>(foreSave.elite_monster_list);
        foreSave.boss_list = new ArrayList<>(foreSave.boss_list);
        foreSave.path_x = new ArrayList<>(foreSave.path_x);
        foreSave.path_y = new ArrayList<>(foreSave.path_y);
        return foreSave;
    }

    public static void trueCopy(SaveFile foreSave,SaveFile save){
        save.level_name = foreSave.level_name;
        save.act_num=foreSave.act_num;
        save.floor_num = foreSave.floor_num;
        save.event_list= foreSave.event_list;
        save.monster_list=foreSave.monster_list;
        save.elite_monster_list= foreSave.elite_monster_list;
        save.boss_list= foreSave.boss_list;
        save.boss= foreSave.boss;
        save.path_x= foreSave.path_x;
        save.path_y= foreSave.path_y;
        save.room_x= foreSave.room_x;
        save.room_y= foreSave.room_y;
        save.spirit_count= foreSave.spirit_count;
        save.current_room= foreSave.current_room;
        save.post_combat= true;
        save.combat_rewards = new ArrayList<>();

        logger.info("TRUECOPY===当前怪物数量："+foreSave.monster_list.size()+" ，怪物列表："+foreSave.monster_list.toString()+" ===");
    }

    //仅在进入树洞后启用，save表示树洞时存档（保存地图外的信息），foreSave表示洞前存档（主要保存地图）
    public static void saveFore(SaveFile save, SaveFile foreSave){
        //需要更新的
        foreSave.floor_num = AbstractDungeon.floorNum;


        HashMap<Object,Object> params = new HashMap<>();
        params.put("name",save.name);
        params.put("loadout", save.loadout);
        params.put("current_health", save.current_health);
        params.put("max_health", save.max_health);
        params.put("max_orbs", save.max_orbs);
        params.put("gold", save.gold);
        params.put("hand_size", save.hand_size);
        params.put("red", save.red);
        params.put("green", save.green);
        params.put("blue", save.blue);
        params.put("monsters_killed", save.monsters_killed);
        params.put("elites1_killed", save.elites1_killed);
        params.put("elites2_killed", save.elites2_killed);
        params.put("elites3_killed", save.elites3_killed);
        params.put("gold_gained", save.gold_gained);
        params.put("mystery_machine", save.mystery_machine);
        params.put("champions", save.champions);
        params.put("perfect", save.perfect);
        params.put("overkill", save.overkill);
        params.put("combo", save.combo);
        params.put("cards", save.cards);
        params.put("obtained_cards", save.obtained_cards);
        params.put("relics", save.relics);
        params.put("relic_counters", save.relic_counters);
        params.put("potions", save.potions);
        params.put("potion_slots", save.potion_slots);
        params.put("is_endless_mode", save.is_endless_mode);
        params.put("blights", save.blights);
        params.put("blight_counters", save.blight_counters);
        params.put("endless_increments", save.endless_increments);
        params.put("chose_neow_reward", save.chose_neow_reward);
        params.put("neow_bonus", save.neow_bonus);
        params.put("neow_cost", save.neow_cost);
        params.put("is_ascension_mode", save.is_ascension_mode);
        params.put("ascension_level", save.ascension_level);

        //fore
        params.put("level_name", foreSave.level_name);

        params.put("floor_num", save.floor_num);
        //fore
        params.put("act_num",foreSave.act_num);
        params.put("event_list", foreSave.event_list);//deep

        params.put("one_time_event_list", save.one_time_event_list);//deep
        params.put("potion_chance", save.potion_chance);
        params.put("event_chances", save.event_chances);//deep
        //fore
        params.put("monster_list", foreSave.monster_list);//deep
        params.put("elite_monster_list", foreSave.elite_monster_list);//deep
        params.put("boss_list", foreSave.boss_list);//deep

        params.put("play_time", save.play_time);
        params.put("save_date", save.save_date);
        params.put("seed", save.seed);
        params.put("special_seed", save.special_seed);
        params.put("seed_set", save.seed_set);
        params.put("is_daily", save.is_daily);
        params.put("is_final_act_on", save.is_final_act_on);
        params.put("has_ruby_key", save.has_ruby_key);
        params.put("has_emerald_key", save.has_emerald_key);
        params.put("has_sapphire_key", save.has_sapphire_key);
        params.put("daily_date", save.daily_date);
        params.put("is_trial", save.is_trial);
        params.put("daily_mods", save.daily_mods);
        params.put("custom_mods", save.custom_mods);
        //fore
        params.put("boss", foreSave.boss);

        params.put("purgeCost", save.purgeCost);
        params.put("monster_seed_count", save.monster_seed_count);
        params.put("event_seed_count", save.event_seed_count);
        params.put("merchant_seed_count", save.merchant_seed_count);
        params.put("card_seed_count", save.card_seed_count);
        params.put("treasure_seed_count", save.treasure_seed_count);
        params.put("relic_seed_count", save.relic_seed_count);
        params.put("potion_seed_count", save.potion_seed_count);
        params.put("ai_seed_count", save.ai_seed_count);
        params.put("shuffle_seed_count", save.shuffle_seed_count);
        params.put("card_random_seed_count", save.card_random_seed_count);
        params.put("card_random_seed_randomizer", save.card_random_seed_randomizer);
        //fore
        params.put("path_x", foreSave.path_x);//deep
        params.put("path_y", foreSave.path_y);//deep
        params.put("room_x", foreSave.room_x);
        params.put("room_y", foreSave.room_y);
        params.put("spirit_count", foreSave.spirit_count);
        params.put("current_room", foreSave.current_room);

        params.put("common_relics", save.common_relics);
        params.put("uncommon_relics", save.uncommon_relics);
        params.put("rare_relics", save.rare_relics);
        params.put("shop_relics", save.shop_relics);
        params.put("boss_relics", save.boss_relics);

        //为确保从树洞离开，一定是true
        params.put("post_combat", true);

        params.put("mugged", save.mugged);
        params.put("smoked", save.smoked);
        params.put("combat_rewards", save.combat_rewards);

        if (AbstractDungeon.player.hasRelic("Bottled Flame")) {
            saveBottle(params, "Bottled Flame", "bottled_flame", ((BottledFlame)AbstractDungeon.player.getRelic("Bottled Flame")).card);
        } else {
            params.put("bottled_flame", (Object)null);
        }

        if (AbstractDungeon.player.hasRelic("Bottled Lightning")) {
            saveBottle(params, "Bottled Lightning", "bottled_lightning", ((BottledLightning)AbstractDungeon.player.getRelic("Bottled Lightning")).card);
        } else {
            params.put("bottled_lightning", (Object)null);
        }

        if (AbstractDungeon.player.hasRelic("Bottled Tornado")) {
            saveBottle(params, "Bottled Tornado", "bottled_tornado", ((BottledTornado)AbstractDungeon.player.getRelic("Bottled Tornado")).card);
        } else {
            params.put("bottled_tornado", (Object)null);
        }

        //fore
        params.put("metric_campfire_rested", save.metric_campfire_rested);
        params.put("metric_campfire_upgraded", save.metric_campfire_upgraded);
        params.put("metric_campfire_rituals", save.metric_campfire_rituals);
        params.put("metric_campfire_meditates", save.metric_campfire_meditates);
        params.put("metric_purchased_purges", save.metric_purchased_purges);
        params.put("metric_potions_floor_spawned", save.metric_potions_floor_spawned);
        params.put("metric_potions_floor_usage", save.metric_potions_floor_usage);
        params.put("metric_current_hp_per_floor", save.metric_current_hp_per_floor);
        params.put("metric_max_hp_per_floor", save.metric_max_hp_per_floor);
        params.put("metric_gold_per_floor", save.metric_gold_per_floor);
        params.put("metric_path_per_floor", save.metric_path_per_floor);
        params.put("metric_path_taken", save.metric_path_taken);
        params.put("metric_items_purchased", save.metric_items_purchased);
        params.put("metric_item_purchase_floors", save.metric_item_purchase_floors);
        params.put("metric_items_purged", save.metric_items_purged);
        params.put("metric_items_purged_floors", save.metric_items_purged_floors);
        params.put("metric_card_choices", save.metric_card_choices);
        params.put("metric_event_choices", save.metric_event_choices);
        params.put("metric_boss_relics", save.metric_boss_relics);
        params.put("metric_damage_taken", save.metric_damage_taken);
        params.put("metric_potions_obtained", save.metric_potions_obtained);
        params.put("metric_relics_obtained", save.metric_relics_obtained);
        params.put("metric_campfire_choices", save.metric_campfire_choices);
        params.put("metric_build_version", save.metric_build_version);
        params.put("metric_seed_played", save.metric_seed_played);
        params.put("metric_floor_reached", save.metric_floor_reached);

        params.put("metric_playtime", save.metric_playtime);

        Gson gson = (new GsonBuilder()).setPrettyPrinting().create();
        String data = gson.toJson(params);
        String filepath = getPlayerSavePath(AbstractDungeon.player.chosenClass);
        if (Settings.isBeta) {
            AsyncSaver.save(filepath + "BETA", data);
        }

        AsyncSaver.save(filepath, SaveFileObfuscator.encode(data, "key"));
    }

    public static void saveExtra(ExtraSave extraSave) {
        String data = new Gson().toJson(extraSave);
        String filepath = getExtraSavePath(AbstractDungeon.player.chosenClass);
        if (Settings.isBeta) {
            AsyncSaver.save(filepath + "BETA", data);
        }
        AsyncSaver.save(filepath, SaveFileObfuscator.encode(data, "key"));
    }

    public static void saveTreeHoleSave(TreeHoleSave treeHoleSave,Class<?> saveClass){
        Gson gson = (new GsonBuilder()).setPrettyPrinting().create();
        String data = gson.toJson(treeHoleSave);
        String filepath = getTreeHoleSavePath(AbstractDungeon.player.chosenClass,saveClass);
        if (Settings.isBeta) {
            AsyncSaver.save(filepath + "BETA", data);
        }
        AsyncSaver.save(filepath, SaveFileObfuscator.encode(data, "key"));
    }

    private static String loadSaveString(String filePath) {
        FileHandle file = Gdx.files.local(filePath);
        String data = file.readString();
        return SaveFileObfuscator.isObfuscated(data) ? SaveFileObfuscator.decode(data, "key") : data;
    }

    public static SaveFile loadSaveFore(AbstractPlayer.PlayerClass c) {
        String fileName = getPlayerSavePath(c);

        try {
            return loadSaveFore(fileName);
        } catch (SaveFileLoadError var3) {
            return null;
        }
    }

    private static SaveFile loadSaveFore(String filePath) throws SaveFileLoadError{
        SaveFile saveFile = null;
        Gson gson = new Gson();
        String savestr = null;
        Exception err = null;

        try {
            savestr = loadSaveString(filePath);
            saveFile = gson.fromJson(savestr,SaveFile.class);
        } catch (Exception var6) {
            if (Gdx.files.local(filePath).exists()) {
                SaveHelper.preserveCorruptFile(filePath);
            }

            err = var6;
            if (!filePath.endsWith(".backUp")) {
                return loadSaveFore(filePath + ".backUp");
            }
        }

        if (saveFile == null) {
            throw new SaveFileLoadError("Didn't Find Right Now: " + filePath, err);
        } else {
            return saveFile;
        }
    }

    public static ExtraSave loadExtra(AbstractPlayer.PlayerClass c) {
        String fileName = getExtraSavePath(c);

        try {
            return loadExtra(fileName);
        } catch (SaveFileLoadError var3) {
            return null;
        }
    }

    private static ExtraSave loadExtra(String filePath) throws SaveFileLoadError{
        ExtraSave saveFile = null;
        Gson gson = new Gson();
        String savestr = null;
        Exception err = null;

        try {
            savestr = loadSaveString(filePath);
            saveFile = gson.fromJson(savestr,ExtraSave.class);
        } catch (Exception var6) {
            if (Gdx.files.local(filePath).exists()) {
                SaveHelper.preserveCorruptFile(filePath);
            }

            err = var6;
            if (!filePath.endsWith(".backUp")) {
                return loadExtra(filePath + ".backUp");
            }
        }

        if (saveFile == null) {
            throw new SaveFileLoadError("Didn't Find Right Now: " + filePath, err);
        } else {
            return saveFile;
        }
    }

    public static TreeHoleSave loadTreeHole(AbstractPlayer.PlayerClass c,Class<?> saveClass) {
        String fileName = getTreeHoleSavePath(c,saveClass);

        try {
            return loadTreeHole(fileName,saveClass);
        } catch (SaveFileLoadError var3) {
            return null;
        }
    }

    private static TreeHoleSave loadTreeHole(String filePath,Class<?> saveClass) throws SaveFileLoadError{
        TreeHoleSave saveFile = null;
        Gson gson = new Gson();
        String savestr = null;
        Exception err = null;

        try {
            savestr = loadSaveString(filePath);
            saveFile = (TreeHoleSave) gson.fromJson(savestr,saveClass);
        } catch (Exception var6) {
            if (Gdx.files.local(filePath).exists()) {
                SaveHelper.preserveCorruptFile(filePath);
            }

            err = var6;
            if (!filePath.endsWith(".backUp")) {
                return loadTreeHole(filePath + ".backUp",saveClass);
            }
        }

        if (saveFile == null) {
            throw new SaveFileLoadError("Didn't Find Right Now: " + filePath, err);
        } else {
            return saveFile;
        }
    }

    public static void deleteSaveFore(AbstractPlayer.PlayerClass chosenClass) {
        String savePath = getPlayerSavePath(chosenClass);
        Gdx.files.local(savePath).delete();
        Gdx.files.local(savePath + ".backUp").delete();
    }

    public static void deleteExtra(AbstractPlayer.PlayerClass chosenClass){
        String savePath = getExtraSavePath(chosenClass);
        Gdx.files.local(savePath).delete();
        Gdx.files.local(savePath + ".backUp").delete();
    }

    public static void deleteTreeHole(AbstractPlayer.PlayerClass chosenClass,Class<?> saveClass){
        String savePath = getTreeHoleSavePath(chosenClass,saveClass);
        Gdx.files.local(savePath).delete();
        Gdx.files.local(savePath + ".backUp").delete();
    }

    private static String getPlayerSavePath(AbstractPlayer.PlayerClass c) {
        StringBuilder sb = new StringBuilder();
        sb.append("saves" + File.separator);
        if (CardCrawlGame.saveSlot != 0) {
            sb.append(CardCrawlGame.saveSlot).append("_");
        }

        sb.append(c.name()).append("_fore_treehole.autosave");
        return sb.toString();
    }

    private static String getExtraSavePath(AbstractPlayer.PlayerClass c){
        StringBuilder sb = new StringBuilder();
        sb.append("saves" + File.separator);
        if (CardCrawlGame.saveSlot != 0) {
            sb.append(CardCrawlGame.saveSlot).append("_");
        }

        sb.append(c.name()).append("_extra_treehole.autosave");
        return sb.toString();
    }

    private static String getTreeHoleSavePath(AbstractPlayer.PlayerClass c,Class<?> className){
        StringBuilder sb = new StringBuilder();
        sb.append("saves" + File.separator);
        if (CardCrawlGame.saveSlot != 0) {
            sb.append(CardCrawlGame.saveSlot).append("_");
        }

        sb.append(c.name()).append("_"+className.getSimpleName()+"_treehole.autosave");
        return sb.toString();
    }

    private static void saveBottle(HashMap<Object, Object> params, String bottleId, String save_name, AbstractCard card) {
        if (AbstractDungeon.player.hasRelic(bottleId)) {
            if (card != null) {
                params.put(save_name, card.cardID);
                params.put(save_name + "_upgrade", card.timesUpgraded);
                params.put(save_name + "_misc", card.misc);
            } else {
                params.put(save_name, (Object)null);
            }
        } else {
            params.put(save_name, (Object)null);
        }

    }
}

